﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Physis.Security {

    public class Role : Core.CoreConfigurationObject {
        
        #region Private Properties

        private Int64 environmentId = 0;


        private List<RoleMembership> membership = null;

        private List<RolePermission> permissions = null;
        
        #endregion 


        #region Public Properties

        public Int64 EnvironmentId { get { return environmentId; } set { environmentId = value; } }

        [System.Web.Script.Serialization.ScriptIgnore]
        public Enterprise.Environment Environment { get { return Application.Enterprise.Environment (environmentId, true); } }

        public String EnvironmentName { get { return ((Environment != null) ? Environment.Name : String.Empty); } }


        public List<RoleMembership> Membership {

            get {

                if (membership == null) { LoadChildObjects ();  }

                return membership;

            }

            set { 
                
                membership = value;

                foreach (RoleMembership currentRoleMembership in membership) {

                    currentRoleMembership.Application = Application;

                    currentRoleMembership.RoleId = Id;

                }

            }

        }

        public List<RolePermission> Permissions {

            get {

                if (permissions == null) { LoadChildObjects (); }

                return permissions;

            }

            set { 
                
                permissions = value;

                foreach (RolePermission currentRolePermission in permissions) {

                    currentRolePermission.Application = Application;

                    currentRolePermission.RoleId = Id;

                }

            }

        }

        #endregion 

        
        #region Constructors

        public Role (Application forApplication) : base (forApplication) {

            return;

        }

        public Role (Application forApplication, Int64 forId) : base (forApplication) {

            if (!Load (forId, Application.EnterpriseDatabase)) {

                throw new Exception (GetType ().FullName + ".Load [Failed]: " + forId);

            }

            return;

        }

        public Role (Application forApplication, String forName) : base (forApplication) {

            if (!Load (forName, Application.EnterpriseDatabase)) {

                throw new Exception (GetType ().FullName + ".Load [Failed]: " + forName);

            }

            return;

        }

        #endregion


        #region Database Functions 

        public override void MapDataFields (System.Data.DataRow currentRow) {

            base.MapDataFields (currentRow);

            environmentId = Data.Readers.DataReader.Int64FromDatabase (currentRow, "EnvironmentId");

            return;

        }

        protected override Boolean LoadChildObjects () {

            membership = Application.Security.RoleMembership (Id);


            // FILTER OUT THE PERMISSIONS TO ENTERPRISE PERMISSIONS IF ENTERPRISE ROLE OR TO ENVIRONMENT IF ENVIRONMENT ROLE 

            permissions = Application.Security.RolePermissions (Id);

            if (environmentId == 0) {

                permissions = (from currentPermission in permissions where currentPermission.Name.StartsWith ("Enterprise.") select currentPermission).ToList ();

            }

            else {

                permissions = (from currentPermission in permissions where currentPermission.Name.StartsWith ("Environment.") select currentPermission).ToList ();

            }

            return true; // HARD CODED FOR NOW

        }

        public override Boolean Save () {

            Boolean success = false;

            String deleteStatement; 

            try {

                Dictionary<String, String> validationErrors = Validate ();

                if (validationErrors.Count > 0) {

                    Application.SetLastException (new Exception ("Invalid [" + validationErrors.Keys.First () + "]: " + validationErrors.Values.First ()));

                    return false;

                }

                UpdateModifiedToSessionUser ();


                Application.EnterpriseDatabase.BeginTransaction ();

                System.Data.IDbCommand command = Application.EnterpriseDatabase.CreateCommand (ObjectType + "_InsertUpdate");

                command.CommandType = System.Data.CommandType.StoredProcedure;


                Application.EnterpriseDatabase.AppendCommandParameter (command, "Id", Id);

                Application.EnterpriseDatabase.AppendCommandParameter (command, "Name", Name, 60);

                Application.EnterpriseDatabase.AppendCommandParameter (command, "Description", Description, 999);


                Application.EnterpriseDatabase.AppendCommandParameter (command, "EnvironmentId", ((environmentId == 0) ? (Int64?)null : (Int64?)environmentId));


                Application.EnterpriseDatabase.AppendCommandParameter (command, "ModifiedId", Application.Session.UserAccountName, 60);

                success = (command.ExecuteNonQuery () > 0);

                if (success) { SetIdentity (Application.EnterpriseDatabase); }


                deleteStatement = "DELETE FROM RolePermission WHERE RoleId = " + Id;

                success = Application.EnterpriseDatabase.ExecuteSqlStatement (deleteStatement);

                if (!success) { throw Application.EnterpriseDatabase.LastException; }


                deleteStatement = "DELETE FROM RoleMembership WHERE RoleId = " + Id;

                success = Application.EnterpriseDatabase.ExecuteSqlStatement (deleteStatement);

                if (!success) { throw Application.EnterpriseDatabase.LastException; }


                foreach (RolePermission currentRolePermission in Permissions) {

                    currentRolePermission.Application = Application;

                    currentRolePermission.RoleId = Id;

                    success = success && (currentRolePermission.Save ());

                    if (!success) { throw Application.EnterpriseDatabase.LastException; }

                }

                foreach (RoleMembership currentRoleMembership in Membership) {

                    currentRoleMembership.Application = Application;

                    currentRoleMembership.RoleId = Id;

                    success = success && (currentRoleMembership.Save ());

                    if (!success) { throw Application.EnterpriseDatabase.LastException; }

                }

                Application.EnterpriseDatabase.CommitTransaction ();

            }

            catch (Exception exception) {

                Application.EnterpriseDatabase.RollbackTransaction ();

                success = false;

                Application.SetLastException (exception);

            }

            return success; 
            
        }

        public override Boolean Delete () {

            Boolean success = false;

            String deleteStatement;

            try {

                Application.EnterpriseDatabase.BeginTransaction ();


                // DELETE CHILD RECORDS IN THE RELATIONSHIP 

                deleteStatement = "DELETE FROM RolePermission WHERE RoleId = " + Id;

                success = Application.EnterpriseDatabase.ExecuteSqlStatement (deleteStatement);

                if (!success) { throw Application.EnterpriseDatabase.LastException; }


                deleteStatement = "DELETE FROM RoleMembership WHERE RoleId = " + Id;

                success = Application.EnterpriseDatabase.ExecuteSqlStatement (deleteStatement);

                if (!success) { throw Application.EnterpriseDatabase.LastException; }


                success = success && base.DeleteFromDatabase (DeleteStatementById (), Application.EnterpriseDatabase);

                if (!success) { throw Application.EnterpriseDatabase.LastException; }


                Application.EnterpriseDatabase.CommitTransaction ();

            }

            catch (Exception exception) {

                Application.EnterpriseDatabase.RollbackTransaction ();

                success = false;

                Application.SetLastException (exception);

            }

            return success; 
            

        }

        #endregion 


        #region Public Methods

        public RolePermission Permission (Int64 permissionId) {

            foreach (RolePermission currentRolePermission in Permissions) {

                if (currentRolePermission.PermissionId == permissionId) {

                    return currentRolePermission;

                }

            }

            return null;

        }

        #endregion 


    }

}
